package com.xiaowu.house.house.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaowu.house.config.domain.dto.DictionaryDataDTO;
import com.xiaowu.house.config.domain.entity.SysDictionaryData;
import com.xiaowu.house.config.mapper.SysDictionaryDataMapper;
import com.xiaowu.house.config.service.ISysDictionaryService;
import com.xiaowu.house.domain.ResultCode;
import com.xiaowu.house.domain.dto.BasePageDTO;
import com.xiaowu.house.exception.ServiceException;
import com.xiaowu.house.house.constants.HouseConstants;
import com.xiaowu.house.house.domain.dto.*;
import com.xiaowu.house.house.domain.entity.*;
import com.xiaowu.house.house.domain.enums.HouseStatusEnum;
import com.xiaowu.house.house.mapper.*;
import com.xiaowu.house.house.service.IHouseService;
import com.xiaowu.house.map.domain.entity.SysRegion;
import com.xiaowu.house.map.mapper.RegionMapper;
import com.xiaowu.house.service.RedisService;
import com.xiaowu.house.service.RedissonLockService;
import com.xiaowu.house.user.domain.entity.AppUser;
import com.xiaowu.house.user.mapper.AppUserMapper;
import com.xiaowu.house.utils.BeanUtil;
import com.xiaowu.house.utils.JsonUtil;
import com.xiaowu.house.utils.TimestampUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class HouseServiceImpl implements IHouseService {

    @Autowired
    private HouseMapper houseMapper;

    @Autowired
    private AppUserMapper appUserMapper;

    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private CityHouseMapper cityHouseMapper;

    @Autowired
    private TagHouseMapper tagHouseMapper;

    @Autowired
    private HouseStatusMapper houseStatusMapper;

    @Autowired
    private ISysDictionaryService sysDictionaryService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedissonLockService redissonLockService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addOrEdit(HouseAddOrEditReqDTO houseAddOrEditReqDTO) {
        checkAddOrEditReq(houseAddOrEditReqDTO);

        //设置房源基本信息
        House house = new House();
        convertToDO(houseAddOrEditReqDTO, house);

        if (null != houseAddOrEditReqDTO.getHouseId()) {
            house.setId(houseAddOrEditReqDTO.getHouseId());

            House existHouse = houseMapper.selectById(houseAddOrEditReqDTO.getHouseId());
            //检查城市房源映射信息是否需要更新
            if (cityHouseNeedChange(existHouse, houseAddOrEditReqDTO.getCityId())) {
                editCityHouses(houseAddOrEditReqDTO.getHouseId(), existHouse.getCityId(),
                        houseAddOrEditReqDTO.getCityId(), houseAddOrEditReqDTO.getCityName());
            }
            //检查标签房源映射信息是否需要更新
            List<TagHouse> tagHouses = tagHouseMapper.selectList(
                    new LambdaQueryWrapper<TagHouse>()
                    .eq(TagHouse::getHouseId, existHouse.getId()));
            if (TagHouseNeedChange(tagHouses, houseAddOrEditReqDTO.getTagCodes())) {
                editTagHouses(houseAddOrEditReqDTO.getHouseId(),
                        tagHouses, houseAddOrEditReqDTO.getTagCodes());
            }
        }
        houseMapper.insertOrUpdate(house);

        //新增
        if (null == houseAddOrEditReqDTO.getHouseId()) {
            HouseStatus houseStatus = new HouseStatus();

            houseStatus.setHouseId(house.getId());
            houseStatus.setStatus(HouseStatusEnum.UP.name());

            houseStatusMapper.insert(houseStatus);

            // MySQL, Redis
            addCityHouse(house.getId(), house.getCityId(), house.getCityName());

            // MySQL
            addTagHouses(house.getId(), houseAddOrEditReqDTO.getTagCodes());
        }

        //缓存房源完整信息
        cacheHouse(house.getId());

        return house.getId();

    }

    @Override
    public HouseDTO detail(Long houseId) {
        //校验参数
        if (null == houseId || houseId <= 0) {
            log.warn("要查询的房源ID为空或无效");
            return null;
        }

        //先查询缓存
        HouseDTO houseDTO = redisService.getCacheObject(
                HouseConstants.HOUSE_PREFIX + houseId, HouseDTO.class);
        //判断缓存是否存在
        if (null != houseDTO) {
            return houseDTO;
        }

        //缓存不存在查询MySQL
        houseDTO = getHouseDTOById(houseId);

        //MySQL不存在，缓存空对象(解决缓存穿透)
        if (null == houseDTO) {
            cacheNullHouse(houseId, 60L);
        }
        //缓存房源信息
        cacheHouse(houseDTO);

        return houseDTO;
    }

    @Override
    public BasePageDTO<HouseDescDTO> list(HouseListReqDTO houseListReqDTO) {
        BasePageDTO<HouseDescDTO> result = new BasePageDTO<>();

        //查询总数
        Long totals = houseMapper.selectCountWithStatus(houseListReqDTO);

        if (0 == totals) {
            result.setTotals(0);
            result.setTotalPages(0);
            result.setList(Arrays.asList());
            log.info("查询的房源列表为空，HouseListReqDTO:{}", JsonUtil.obj2String(houseListReqDTO));
            return result;
        }

        houseListReqDTO.setOffset(houseListReqDTO.getOffset());

        //查询列表
        List<HouseDescDTO> houses = houseMapper.selectPageWithStatus(houseListReqDTO);
        result.setTotals(
                Integer.parseInt(
                        String.valueOf(totals)));
        result.setTotalPages(
                BasePageDTO.calculateTotalPages(totals, houseListReqDTO.getPageSize()));
        if (CollectionUtils.isEmpty(houses)) {
            log.info("超出查询房源列表范围！HouseListReqDTO:{}", JsonUtil.obj2String(houseListReqDTO));
            result.setList(Arrays.asList());
            return result;
        }
        result.setList(houses);
        return result;
    }

    @Override
    public void editStatus(HouseStatusEditReqDTO houseStatusEditReqDTO) {
        //校验房源是否存在
        House house = houseMapper.selectById(houseStatusEditReqDTO.getHouseId());
        if (null == house) {
            throw new ServiceException("房源不存在，无法修改状态！");
        }

        //更新状态表
        HouseStatus houseStatus = houseStatusMapper.selectOne(
                new LambdaQueryWrapper<HouseStatus>()
                        .eq(HouseStatus::getHouseId, houseStatusEditReqDTO.getHouseId()));
        if (null == houseStatus || StringUtils.isEmpty(houseStatus.getStatus())) {
            throw new ServiceException("房源状态不存在，无法修改状态");
        }

        HouseStatusEnum houseStatusEnum = HouseStatusEnum.getByName(houseStatusEditReqDTO.getStatus());
        if (null == houseStatusEnum) {
            throw new ServiceException("要修改的房源状态有误，无法修改状态");
        }

        houseStatus.setStatus(houseStatusEnum.name());

        if (HouseStatusEnum.RENTING.name()
                .equalsIgnoreCase(houseStatusEditReqDTO.getStatus())) {

            //校验是否传了出租时长码
            if (StringUtils.isEmpty(houseStatusEditReqDTO.getRentTimeCode())) {
                throw new ServiceException("出租时长不能为空，无法修改状态！");
            }
            houseStatus.setRentTimeCode(houseStatusEditReqDTO.getRentTimeCode());
            houseStatus.setRentStartTime(TimestampUtil.getCurrentMillis());
            switch (houseStatusEditReqDTO.getRentTimeCode()) {
                case HouseConstants.RENT_ONE_YEAR -> houseStatus.setRentEndTime(
                        TimestampUtil.getYearLaterMillis(1L));
                case HouseConstants.RENT_HALF_YEAR -> houseStatus.setRentEndTime(
                        TimestampUtil.getMonthsLaterMillis(6L));
                case HouseConstants.RENT_THIRTY_SECONDS -> houseStatus.setRentEndTime(
                        TimestampUtil.getSecondsLaterMillis(30L));
                default -> throw new ServiceException("出租时长错误，无法修改状态！");
            }
        }

        houseStatusMapper.updateById(houseStatus);

        cacheHouse(houseStatusEditReqDTO.getHouseId());

    }

    /**
     * 缓存空对象
     * @param houseId 房源ID
     * @param timeout 过期时间
     */
    private void cacheNullHouse(Long houseId, long timeout) {
        if (null == houseId) {
            log.warn("要缓存的房源ID为空");
            return;
        }

        try {
            redisService.setCacheObject(
                    HouseConstants.HOUSE_PREFIX + houseId,
                    JsonUtil.obj2String(new HouseDTO()), timeout, TimeUnit.SECONDS);
        }catch (Exception e) {
            log.error("缓存空房源完整信息时发生异常，houseId:{}", houseId, e);
            // 对于房源完整信息，是否存在于redis，不需要强一致性。
            // 因为C端查询时，如果redis不存在，可以通过查MySQL获取到数据，让后再放入Redis。
            // throw e;
        }
    }

    /**
     * 缓存房源完整数据 houseDTO
     * @param houseDTO 房源完整数据
     */
    private void cacheHouse(HouseDTO houseDTO) {
        if (null == houseDTO) {
            log.warn("要缓存的房源信息为空");
            return;
        }

        //缓存
        try {
            redisService.setCacheObject(
                    HouseConstants.HOUSE_PREFIX + houseDTO.getHouseId(),
                    JsonUtil.obj2String(houseDTO));
        }catch (Exception e) {
            log.error("缓存房源完整信息时发生异常，houseDTO:{}",
                    JsonUtil.obj2String(houseDTO), e);
        }
    }

    /**
     * 缓存房源信息
     * @param houseId 房源ID
     */
    @Override
    public void cacheHouse(Long houseId) {
        if (null == houseId) {
            log.warn("要缓存的房源ID为空");
            return;
        }

        //通过ID查询完整信息
        HouseDTO hoseDTO = getHouseDTOById(houseId);
        if (null == hoseDTO) {
            log.warn("缓存信息时，查询房源信息错误！");
            return;
        }

        cacheHouse(hoseDTO);
    }

    @Override
    public List<Long> listByUserId(Long userId) {

        if (null == userId) {
            return Arrays.asList();
        }

        List<House> houses = houseMapper.selectList(
                new LambdaQueryWrapper<House>().eq(House::getUserId, userId)
        );

        return houses.stream().map(House::getId)
                .distinct().collect(Collectors.toList());
    }

    @Override
    public void refreshHouseIds() {
        // 获取所有城市列表
        List<SysRegion> regions = regionMapper.selectList(
                new LambdaQueryWrapper<SysRegion>().eq(SysRegion::getLevel, "2")
        );
        for (SysRegion region : regions) {
            Long cityId = region.getId();
            List<CityHouse> cityHouses = cityHouseMapper.selectList(
                    new LambdaQueryWrapper<CityHouse>().eq(CityHouse::getCityId, cityId)
            );
            //删除所有缓存的房源列表
            redisService.removeForAllList(HouseConstants.CITY_HOUSE_PREFIX + cityId);
            if (!CollectionUtils.isEmpty(cityHouses)) {
                redisService.setCacheList(HouseConstants.CITY_HOUSE_PREFIX + cityId,
                        cityHouses.stream().map(CityHouse::getHouseId)
                                .distinct().collect(Collectors.toList()));
            }

            //更新房源详情
            for (CityHouse cityHouse : cityHouses) {
                cacheHouse(cityHouse.getHouseId());
            }
        }
    }

    /**
     * 根据房源ID查询房源DTO
     * @param houseId 房源ID
     * @return HouseDTO
     */
    private HouseDTO getHouseDTOById(Long houseId) {
        if (null == houseId) {
            log.warn("要查询的房源ID为空");
            return null;
        }

        House house = houseMapper.selectById(houseId);
        if (null == house) {
            log.warn("查询房源失败，houseId:{}", houseId);
            return null;
        }

        //根据房源信息校验房东信息
        AppUser appUser = appUserMapper.selectById(house.getUserId());
        if (null == appUser) {
            log.warn("要查询的房源房东信息不存在，houseId:{}, userId{}", houseId, house.getUserId());
            return null;
        }

        HouseStatus houseStatus = houseStatusMapper
                .selectOne(new LambdaQueryWrapper<HouseStatus>()
                        .eq(HouseStatus::getHouseId, houseId));
        if (null == houseStatus) {
            log.warn("要查询的房源状态信息不存在, houseId:{}", houseId);
            return null;
        }

        List<TagHouse> tagHouseList = tagHouseMapper
                .selectList(new LambdaQueryWrapper<TagHouse>()
                        .eq(TagHouse::getHouseId, houseId));

        // 组装完整的房源信息
        return convertToHouseDTO(house, houseStatus, appUser, tagHouseList);
    }

    /**
     * 组装房源完整信息
     * @param house 房源信息
     * @param houseStatus 房源状态
     * @param appUser 房东信息
     * @param tagHouseList 房源标签列表
     * @return 房源完整信息
     */
    private HouseDTO convertToHouseDTO(House house, HouseStatus houseStatus, AppUser appUser,
                                       List<TagHouse> tagHouseList) {

        //校验数据合法性
        if (null == house || null == houseStatus || null == appUser) {
            log.warn("房源信息不完整！");
            return null;
        }

        HouseDTO houseDTO = new HouseDTO();
        BeanUtils.copyProperties(house, houseDTO);
        BeanUtils.copyProperties(houseStatus, houseDTO);
        BeanUtils.copyProperties(appUser, houseDTO);

        houseDTO.setArea(house.getArea().doubleValue());
        houseDTO.setPrice(house.getPrice().doubleValue());
        houseDTO.setLongitude(house.getLongitude().doubleValue());
        houseDTO.setLatitude(house.getLatitude().doubleValue());
        houseDTO.setImages(JsonUtil.string2List(house.getImages(), String.class));

        List<String> dataKeys = Arrays.stream(house.getDevices().split(","))
                .distinct().collect(Collectors.toList());

        List<DictionaryDataDTO> deviceDataDTOS
                = sysDictionaryService.getDicDataByKeys(dataKeys);

        List<DeviceDTO> deviceDTOS = deviceDataDTOS.stream().map(dataDTO -> {
            DeviceDTO deviceDTO = new DeviceDTO();
            deviceDTO.setDeviceCode(dataDTO.getDataKey());
            deviceDTO.setDeviceName(dataDTO.getValue());
            return deviceDTO;
        }).collect(Collectors.toList());

        houseDTO.setDevices(deviceDTOS);

        List<String> tagCodes = tagHouseList.stream()
                .map(TagHouse::getTagCode)
                .distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(tagCodes)) {
            List<Tag> tags = tagMapper.selectList(
                    new LambdaQueryWrapper<Tag>().in(Tag::getTagCode, tagCodes));
            houseDTO.setTags(BeanUtil.copyListProperties(tags, TagDTO::new));
        }

        return houseDTO;
    }


    /**
     * 新增房源标签映射信息
     * @param houseId 房源ID
     * @param tagCodes 标签列表
     */
    private void addTagHouses(Long houseId, List<String> tagCodes) {
        List<TagHouse> tagHouseList = tagCodes.stream().map(tagCode -> {
            TagHouse tagHouse = new TagHouse();
            tagHouse.setHouseId(houseId);
            tagHouse.setTagCode(tagCode);

            return tagHouse;
        }).collect(Collectors.toList());

        tagHouseMapper.insert(tagHouseList);
    }


    /**
     * 新增房源城市映射信息
     * @param houseId 房源ID
     * @param cityId 城市ID
     * @param cityName 城市名
     */
    private void addCityHouse(Long houseId, Long cityId, String cityName) {
        CityHouse cityHouse = new CityHouse();
        cityHouse.setHouseId(houseId);
        cityHouse.setCityName(cityName);
        cityHouse.setCityId(cityId);

        cityHouseMapper.insert(cityHouse);

        cacheCityHouses(HouseConstants.HOUSE_INSERT, houseId, cityId, cityId);
    }

    /**
     * 编辑房源标签映射信息
     * @param houseId 房源ID
     * @param oldTagHouses 旧房源标签映射信息
     * @param newTagCodes 新房源标签映射信息
     */
    private void editTagHouses(Long houseId, List<TagHouse> oldTagHouses, List<String> newTagCodes) {
        Set<String> oldTagCodes = oldTagHouses
                .stream().map(TagHouse::getTagCode)
                .collect(Collectors.toSet());
        List<String> deleteTagCodes = oldTagCodes.stream()
                .filter(oldTagCode -> !newTagCodes.contains(oldTagCode))
                .collect(Collectors.toList());

        //删除需要删除的房源标签映射信息
        if (!CollectionUtils.isEmpty(deleteTagCodes)) {
            tagHouseMapper.delete(new LambdaQueryWrapper<TagHouse>()
                    .eq(TagHouse::getHouseId, houseId)
                    .in(TagHouse::getTagCode, deleteTagCodes));
        }

        List<TagHouse> newTagHouses = newTagCodes.stream()
                .filter(newTagCode -> !oldTagCodes.contains(newTagCode))
                .map(newTagCode -> {
                    TagHouse tagHouse = new TagHouse();
                    tagHouse.setTagCode(newTagCode);
                    tagHouse.setHouseId(houseId);
                    return tagHouse;
                }).collect(Collectors.toList());

        //新增需要新增的房源标签映射信息
        if (!CollectionUtils.isEmpty(newTagHouses)) {
            tagHouseMapper.insert(newTagHouses);
        }
    }


    /**
     * 校验房源标签映射信息是否需要更新
     * @param oldTagHouses 旧的房源标签映射信息
     * @param newTagCodes 新的房源标签映射信息
     * @return 是否需要更新房源标签映射信息 true 需要 false 不需要
     */
    private boolean TagHouseNeedChange(List<TagHouse> oldTagHouses, List<String> newTagCodes) {
        List<String> oldTagCodes = oldTagHouses
                .stream().map(TagHouse::getTagCode)
                .sorted()
                .collect(Collectors.toList());

        newTagCodes = newTagCodes.stream().sorted().collect(Collectors.toList());

        return !Objects.equals(oldTagCodes, newTagCodes);
    }

    /**
     * 更新城市房源映射关系
     * @param houseId 房源ID
     * @param oldCityId 旧城市ID
     * @param newCityId 新城市ID
     * @param cityName 新的城市名
     */
    private void editCityHouses(Long houseId, Long oldCityId, Long newCityId, String cityName) {
        //删除老的映射信息
        cityHouseMapper.delete(new LambdaQueryWrapper<CityHouse>()
                .eq(CityHouse::getCityId, oldCityId)
                .eq(CityHouse::getHouseId, houseId));

        CityHouse cityHouse = new CityHouse();
        cityHouse.setCityName(cityName);
        cityHouse.setHouseId(houseId);
        cityHouse.setCityId(newCityId);
        //存储新的映射信息
        cityHouseMapper.insert(cityHouse);

        //缓存城市房源映射关系
        cacheCityHouses(HouseConstants.HOUSE_EDIT, houseId, oldCityId, newCityId);
    }

    /**
     * 缓存城市房源映射信息
     * @param op 逻辑判断值
     * @param houseId 房源ID
     * @param oldCityId 旧城市ID
     * @param newCityId 新城市ID
     */
    private void cacheCityHouses(int op, Long houseId, Long oldCityId, Long newCityId) {
        try {
            //新增逻辑
            if (HouseConstants.HOUSE_INSERT == op) {
                redisService.setCacheList(HouseConstants.CITY_HOUSE_PREFIX + newCityId,
                        Arrays.asList(houseId));
            }
            //编辑逻辑
            else if (HouseConstants.HOUSE_EDIT == op) {
                //先移除旧的缓存数据
                redisService.removeForList(HouseConstants.CITY_HOUSE_PREFIX + oldCityId,
                        houseId);
                //缓存更改后的数据
                redisService.setCacheList(HouseConstants.CITY_HOUSE_PREFIX + newCityId,
                        Arrays.asList(houseId));
            }else {
                log.error("无效的操作:缓存城市房源映射信息");
            }
        }catch (Exception e) {
            log.error("缓存城市下的房源列表发生异常，op:{}, houseId:{}, oldCityId:{}, newCityId:{}",
                    op, houseId, oldCityId, newCityId, e);
            throw e;
        }
    }

    /**
     * 判断是否需要更新城市房源映射关系
     *
     * @param oldHouse 旧房源信息
     * @param newCityId 新的城市ID
     * @return 是否需要更新城市房源映射关系 true 需要 false 不需要
     */
    private boolean cityHouseNeedChange(House oldHouse, Long newCityId) {
        return !oldHouse.getCityId().equals(newCityId);
    }

    /**
     * 设置房源基本信息
     * @param houseAddOrEditReqDTO 请求DTO
     * @param house 房源信息
     */
    private void convertToDO(HouseAddOrEditReqDTO houseAddOrEditReqDTO, House house) {
        house.setArea(BigDecimal.valueOf(houseAddOrEditReqDTO.getArea()));
        house.setAllFloor(houseAddOrEditReqDTO.getAllFloor());
        house.setHouseType(houseAddOrEditReqDTO.getHouseType());
        house.setDevices(
                houseAddOrEditReqDTO.getDevices().stream()
                        .filter(s -> !s.isEmpty())
                        .collect(Collectors.joining(","))
        );
        house.setCityId(houseAddOrEditReqDTO.getCityId());
        house.setCityName(houseAddOrEditReqDTO.getCityName());
        house.setFloor(houseAddOrEditReqDTO.getFloor());
        house.setHeadImage(houseAddOrEditReqDTO.getHeadImage());
        house.setImages(JsonUtil.obj2String(houseAddOrEditReqDTO.getImages()));
        house.setIntro(houseAddOrEditReqDTO.getIntro());
        house.setLatitude(BigDecimal.valueOf(houseAddOrEditReqDTO.getLatitude()));
        house.setPrice(BigDecimal.valueOf(houseAddOrEditReqDTO.getPrice()));
        house.setRegionId(houseAddOrEditReqDTO.getRegionId());
        house.setRentType(houseAddOrEditReqDTO.getRentType());
        house.setRooms(houseAddOrEditReqDTO.getRooms());
        house.setRegionName(houseAddOrEditReqDTO.getRegionName());
        house.setCommunityName(houseAddOrEditReqDTO.getCommunityName());
        house.setUserId(houseAddOrEditReqDTO.getUserId());
        house.setDetailAddress(houseAddOrEditReqDTO.getDetailAddress());
        house.setPosition(houseAddOrEditReqDTO.getPosition());
        house.setTitle(houseAddOrEditReqDTO.getTitle());
        house.setLongitude(BigDecimal.valueOf(houseAddOrEditReqDTO.getLongitude()));
    }


    /**
     * 校验新增或编辑请求参数
     * @param houseAddOrEditReqDTO 请求参数
     */
    private void checkAddOrEditReq(HouseAddOrEditReqDTO houseAddOrEditReqDTO) {

        AppUser user = appUserMapper.selectById(houseAddOrEditReqDTO.getUserId());
        if (user == null) {
            throw new ServiceException(ResultCode.INVALID_PARA.getCode(), "房东信息不存在");
        }

        List<Long> regionIds = Arrays.asList(houseAddOrEditReqDTO.getRegionId(),
                houseAddOrEditReqDTO.getCityId());
        List<SysRegion> regions = regionMapper.selectBatchIds(regionIds);

        if (regionIds.size() != regions.size()) {
            throw new ServiceException(ResultCode.INVALID_PARA.getCode(), "传递的城市信息有误！");
        }

        // 3. 校验标签码
        LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Tag::getTagCode, houseAddOrEditReqDTO.getTagCodes());
        List<Tag> tags = tagMapper.selectList(queryWrapper);
//        houseAddOrEditReqDTO.setTagCodes(
//                houseAddOrEditReqDTO.getTagCodes()
//                        .stream()
//                        .distinct()
//                        .collect(Collectors.toList())
//        );
        if (houseAddOrEditReqDTO.getTagCodes().size() != tags.size()) {
            throw new ServiceException(ResultCode.INVALID_PARA.getCode(), "传递的标签列表有误！");
        }
    }

    //每天凌晨0:00执行
//    @Scheduled(cron = "0 0 0 * * ?")

//    // 每 10s 执行定时任务(测试)
//    @Scheduled(cron = "*/10 * * * * ?")
//    public void scheduledHouseStatus() {
//        log.info("开始执行定时任务:扭转房源状态");
//
//        //生成校验value
//        String value = UUID.randomUUID().toString();
//        try {
//            //获取分布式锁
//
//            Boolean lock = redisService.setCacheObjectIfAbsent(HouseConstants.LOCK_KEY, value,
//                    180L, TimeUnit.SECONDS);
//            if (Boolean.TRUE.equals(lock)) {
//                //查找全量已出租房屋
//                List<HouseStatus> houseStatuses = houseStatusMapper.selectList(
//                        new LambdaQueryWrapper<HouseStatus>()
//                                .eq(HouseStatus::getStatus, HouseStatusEnum.RENTING.name())
//                );
//
//                //过滤出需要修改房屋状态的房源
//                List<HouseStatus> needConvertHouseStatus = houseStatuses.stream()
//                        .filter(houseStatus -> null != houseStatus.getRentTimeCode()
//                                && 0 > TimestampUtil.calculateDifferenceMillis(
//                                        TimestampUtil.getCurrentMillis(), houseStatus.getRentEndTime()))
//                        .collect(Collectors.toList());
//
//                //修改房源状态
//                for (HouseStatus houseStatus : needConvertHouseStatus) {
//                    HouseStatusEditReqDTO houseStatusEditReqDTO = new HouseStatusEditReqDTO();
//                    houseStatusEditReqDTO.setHouseId(houseStatus.getHouseId());
//                    houseStatusEditReqDTO.setStatus(HouseStatusEnum.UP.name());
//                    houseStatusEditReqDTO.setRentTimeCode(houseStatus.getRentTimeCode());
//                    editStatus(houseStatusEditReqDTO);
//                }
//            }else {
//                log.info("定时任务被其他实例执行");
//            }
//
//        } finally {
//            //释放锁
//            redisService.cad(HouseConstants.LOCK_KEY, value);
//
//        }
//    }

//    // 每天凌晨 0:00 执行定时任务
//    @Scheduled(cron = "0 0 0 * * ?")
    //每 10s 执行定时任务(测试)
    @Scheduled(cron = "*/10 * * * * ?")
    public void scheduledHouseStatus() {
        log.info("开始执行定时任务:扭转房源状态");

        // 加 Redisson 分布式锁
        RLock rLock = redissonLockService.acquire(HouseConstants.LOCK_KEY, -1);
        if (null == rLock) {
            log.info("定时任务已被其他实例执行");
            return;
        }
        try {

            //查找全量已出租房屋
            List<HouseStatus> houseStatuses = houseStatusMapper.selectList(
                    new LambdaQueryWrapper<HouseStatus>()
                            .eq(HouseStatus::getStatus, HouseStatusEnum.RENTING.name())
            );

            //过滤出需要修改房屋状态的房源
            List<HouseStatus> needConvertHouseStatus = houseStatuses.stream()
                    .filter(houseStatus -> null != houseStatus.getRentTimeCode()
                            && 0 > TimestampUtil.calculateDifferenceMillis(
                            TimestampUtil.getCurrentMillis(), houseStatus.getRentEndTime()))
                    .collect(Collectors.toList());

            //修改房源状态
            for (HouseStatus houseStatus : needConvertHouseStatus) {
                HouseStatusEditReqDTO houseStatusEditReqDTO = new HouseStatusEditReqDTO();
                houseStatusEditReqDTO.setHouseId(houseStatus.getHouseId());
                houseStatusEditReqDTO.setStatus(HouseStatusEnum.UP.name());
                houseStatusEditReqDTO.setRentTimeCode(houseStatus.getRentTimeCode());
                editStatus(houseStatusEditReqDTO);
            }

        } finally {
            //释放锁
            if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                redissonLockService.releaseLock(rLock);
            }

        }
    }
}
